package com.wxy.ej.flow.modules.taskflow.service;

import com.alibaba.fastjson.JSONObject;
import com.rt.easyjava.common.base.Result;
import com.wxy.ej.flow.modules.taskflow.service.nodeExecuteStrategy.strategy.controller.ControllerBreakNodeStrategy;
import com.wxy.ej.flow.modules.taskflow.service.nodeExecuteStrategy.strategy.controller.ControllerCircleStartNodeStrategy;
import com.wxy.ej.flow.modules.taskflow.service.nodeExecuteStrategy.strategy.controller.ControllerCombineNodeStrategy;
import com.wxy.ej.flow.modules.taskflow.bean.TaskFlow;
import com.wxy.ej.flow.modules.taskflow.dto.DataDto;
import com.wxy.ej.flow.modules.taskflow.dto.NodeDto;
import com.wxy.ej.flow.modules.taskflow.repository.NodeRepository;
import com.wxy.ej.flow.modules.taskflow.repository.mapper.TaskFlowMapper;
import com.wxy.ej.flow.modules.taskflow.service.nodeExecuteStrategy.NodeStrategy;
import com.wxy.ej.flow.modules.taskflow.service.nodeExecuteStrategy.NodeStrategyFactory;
import com.wxy.ej.flow.modules.taskflow.service.nodeExecuteStrategy.strategy.controller.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * BusinessService 接口: 对外提供业务代码服务
 * @author wuxiaoyong
 * @since 2022-01-29
 */
@Slf4j
@Service
@Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
public class TaskflowBizService {
    @Resource
    TaskFlowMapper taskFlowMapper;
    @Resource
    NodeRepository nodeRepository;

    public Result executeTask(long taskFlowId, Map<String, Object> paramMap) {
        TaskFlow taskFlow = taskFlowMapper.selectById(taskFlowId);
        JSONObject flowDataJson = JSONObject.parseObject(taskFlow.getFlowData());

        DataDto dataDto = new DataDto();
        dataDto.setTaskFlowId(taskFlowId);
        dataDto.setUiInParam(paramMap);
        Result result = executeTask(dataDto, flowDataJson);
        // 清空流程所有数据，除日志、ui输出数据
        dataDto.clear();

        // 分页 total
        /*List totalList = (List)dataDto.getUiOutData4PageTotal();
        int total = 0;
        if (totalList!=null && totalList.size()>0){
            Map<String, Object> totalMap = (Map<String, Object>) totalList.get(0);
            total = Integer.parseInt(totalMap.get("total").toString());
        }*/
        int total = 0;
        if (dataDto.getUiOutData4PageTotal()!=null) {
            total = Integer.parseInt(dataDto.getUiOutData4PageTotal().toString());
        }
        // 返回日志列表
        Map<String,Object> resultMap = new HashMap<>();
        resultMap.put("logList", dataDto.getLogList());
        resultMap.put("total", total);
        return result.setObj(dataDto.getUiOutData()).setMap(resultMap);
    }

    private Result executeTask(DataDto dataDto, JSONObject flowDataJson) {
        Result result = null;
        List<NodeDto> startNodeList = nodeRepository.selectStartNodeList(flowDataJson);
        for (NodeDto node:startNodeList) {
            result = executeNode(node, flowDataJson, dataDto);
            dataDto.getLogList().add(result.getContent());
            if (!result.isSuccess()) {
                break;
            }
        }
        return result;
    }

    private Result executeNode(NodeDto node, JSONObject flowDataJson, DataDto dataDto) {
        String type = node.getType();
        NodeStrategy nodeStrategy = NodeStrategyFactory.getStrategy(type);
        // type在factory中不存在
        if (nodeStrategy==null) {
            return Result.builder().fault(type+"不存在");
        }
        // 当前节点执行，失败了就退出整个流程
        Result nodeExcResult = nodeStrategy.templateAction(node, flowDataJson, dataDto);
        if (!nodeExcResult.isSuccess()) {
            return nodeExcResult;
        }

        // 执行 next node
        List<NodeDto> nextNodeList = nodeRepository.selectNextNodeList(node.getId(), flowDataJson);
        if (nextNodeList==null || nextNodeList.isEmpty()) {
            return Result.builder();
        }
        for (NodeDto node1:nextNodeList) {
            // 当前是'break'node: and match break condition and in circle
            if (type.equalsIgnoreCase("controller-break-node")
                    && ControllerBreakNodeStrategy.BreakFlag.equalsIgnoreCase(nodeExcResult.getRemark())
                    && dataDto.isInCircle()
            ) {
                dataDto.setBreak(true);
            }
            // 当前是'continue'node
            if (type.equalsIgnoreCase("controller-continue-node")
                    && ControllerContinueNodeStrategy.ContinueFlag.equalsIgnoreCase(nodeExcResult.getRemark())
                    && dataDto.isInCircle()
            ) {
                dataDto.setContinue(true);
            }

            // 当前是'循环'
            if (type.equalsIgnoreCase("controller-circle-start-node")) {
                //找循环体路由, node1
                boolean isRunBodyLink = nodeRepository.isMethodBody(node1);
                // run circle body run
                if (ControllerCircleStartNodeStrategy.IsCircleBodyContinueRun_True.equalsIgnoreCase(nodeExcResult.getRemark())
                    && isRunBodyLink
                ) {
                    Result r1 = executeNode(node1, flowDataJson, dataDto);
                    if (!r1.isSuccess()) {
                        return r1;
                    }
                    break;
                }
                // run others
                if (ControllerCircleStartNodeStrategy.IsCircleBodyContinueRun_False.equalsIgnoreCase(nodeExcResult.getRemark())
                     && !isRunBodyLink
                ){
                    Result r1 = executeNode(node1, flowDataJson, dataDto);
                    if (!r1.isSuccess()) {
                        return r1;
                    }
                    continue;
                }
                continue;
            }

            // '数据汇聚'节点，未汇聚完成，当前节点的后续就不用执行了
            if (type.equalsIgnoreCase("controller-combine-node") && ControllerCombineNodeStrategy.Combine_NotOk.equalsIgnoreCase(nodeExcResult.getRemark())) {
                break;
            }

            // 'if-start' node
            if (type.equalsIgnoreCase("controller-if-start-node")) {
                //找if body路由, node1
                boolean isRunBodyLink = nodeRepository.isMethodBody(node1);
                // 如果条件是false 执行 '如果止'node
                if (nodeExcResult.getRemark().equalsIgnoreCase(ControllerIfStartNodeStrategy.IfCondition_False) && !isRunBodyLink) {
                    Result r1 = executeNode(node1, flowDataJson, dataDto);
                    if (!r1.isSuccess()) {
                        return r1;
                    }
                    break;
                }
                // 如果条件是true 执行 '如果'node主体
                else if (nodeExcResult.getRemark().equalsIgnoreCase(ControllerIfStartNodeStrategy.IfCondition_True) && isRunBodyLink) {
                    Result r1 = executeNode(node1, flowDataJson, dataDto);
                    if (!r1.isSuccess()) {
                        return r1;
                    }
                    break;
                }
                continue;
            }
            // 'route link' node
            if (type.equalsIgnoreCase("link")) {
                List<NodeDto> preNodeList = nodeRepository.selectPreNodeList(node.getId(), flowDataJson);
                boolean isRouteLink = nodeRepository.hasNodeTypeFromNodeList("controller-route-node", preNodeList);
                // 非路由link, 直接执行
                if (!isRouteLink) {
                    Result r1 = executeNode(node1, flowDataJson, dataDto);
                    if (!r1.isSuccess()) {
                        return r1;
                    }
                    continue;
                }

                log.info("LinkStrategy linkRouteCondition：{}", nodeExcResult.getRemark());
                // 路由link, false break
                if (nodeExcResult.getRemark().equalsIgnoreCase(LinkStrategy.LinkRouteCondition_False)) {
                    break;
                }
                // 路由link,  true, execute next node
                if (nodeExcResult.getRemark().equalsIgnoreCase(LinkStrategy.LinkRouteCondition_True)) {
                    Result r1 = executeNode(node1, flowDataJson, dataDto);
                    if (!r1.isSuccess()) {
                        return r1;
                    }
                    break;
                }
                continue;
            }

            // 其它节点
            Result r1 = executeNode(node1, flowDataJson, dataDto);
            if (!r1.isSuccess()) {
                return r1;
            }
        }

        return Result.builder();
    }

}
